package framework;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class CommonFunctions {

    /**
     * Экземпляр класса создать нельзя; все методы статические
     */
    private CommonFunctions() {
    }

    //====================================================================
    // Методы для работы с регулярными выражениями

    /**
     * Создание объекта шаблона
     * @param regex Шаблон выражения
     * @param matchCase Учитывать ли регистр символов при сравнении
     */
    private static Pattern regexGetPattern(String regex, boolean matchCase) {
        int flags;
        if (matchCase) {
            flags = 0;
        } else {
            flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
        }
        return Pattern.compile(regex, flags);
    }

    /**
     * Получение 1-го совпадения в строке
     */
    public static String regexGetMatch(String text, String regex) {
        return regexGetMatch(text, regex, false);
    }

    /**
     * Получение 1-го совпадения в строке
     */
    public static String regexGetMatch(
            String text, 
            String regex, 
            boolean matchCase) {
        return regexGetMatchGroup(text, regex, 0, matchCase);
    }

    /**
     * Проверка строки на совпадение шаблону
     */
    public static boolean regexIsMatch(String text, String regex) {
        return regexIsMatch(text, regex, false);
    }

    /**
     * Проверка строки на совпадение шаблону
     */
    public static boolean regexIsMatch(
            String text, 
            String regex, 
            boolean matchCase) {
        Pattern p = regexGetPattern(regex, matchCase);
        Matcher m = p.matcher(text);
        return m.find();
    }

    /**
     * Получение 1-ой группы из совпадения
     */
    public static String regexGetMatchGroup(String text, String regex) {
        return regexGetMatchGroup(text, regex, 1, false);
    }

    /**
     * Получение указанной группы из совпадения
     * @param text Текст
     * @param regex Шаблон
     * @param groupIndex Номер группы (начинается с 1)
     */
    public static String regexGetMatchGroup(
            String text, 
            String regex, 
            int groupIndex) {
        return regexGetMatchGroup(text, regex, groupIndex, false);
    }

    /**
     * Получение указанной группы из совпадения
     * @param text Текст
     * @param regex Шаблон
     * @param groupIndex Номер группы (начинается с 1)
     * @param matchCase Учитывать ли регистр символов
     */
    public static String regexGetMatchGroup(
            String text, 
            String regex, 
            int groupIndex, 
            boolean matchCase) {
        Pattern p = regexGetPattern(regex, matchCase);
        Matcher m = p.matcher(text);
        if (m.find()) {
            return m.group(groupIndex);
        } else {
            return null;
        }
    }

    /**
     * Получение кол-ва групп совпадений
     * @param text Текст
     * @param regex Шаблон
     */
    public static int regexGetNumberMatchGroup(String text, String regex) {
        return regexGetNumberMatchGroup(text, regex, false);
    }

    /**
     * Получение кол-ва групп совпадений
     * @param text Текст
     * @param regex Шаблон
     * @param matchCase Учитывать ли регистр символов
     */
    public static int regexGetNumberMatchGroup(
            String text, 
            String regex, 
            boolean matchCase) {
        int number = 0;
        Pattern p = regexGetPattern(regex, matchCase);
        Matcher m = p.matcher(text);
        while (m.find()) {
            m.group();
            number++;
        }
        return number;
    }

    //============================================================
    // Методы для работы с датами

    /**
     * Получение строки с текущей датой по шаблону "dd.MM.yyyy"
     */
    public static String getCurrentDate() {
        return getCurrentDate("dd.MM.yyyy");
    }

    /**
     * Получение строки с текущей датой по указанному шаблону
     */
    public static String getCurrentDate(String pattern) {
        return formatDate(new Date(), pattern);
    }

    /**
     * Получение псевдоуникальной строки, содержащей временную метку
     */
    public static String getTimestamp() {
        return getCurrentDate("yyyyMMddHHmmss");
    }

    /**
     * Перевод строки с датой в объект Calendar
     * @param s Строка с датой
     */
    public static Calendar dateString2Calendar(String s) throws ParseException {
        Calendar cal = Calendar.getInstance();
        Date d1 = new SimpleDateFormat("dd.mm.yyyy").parse(s);
        cal.setTime(d1);
        return cal;
    }

    /**
     * Перевести указанную дату в строку по шаблону
     * @param date Дата
     * @param pattern Шаблон даты
     */
    public static String formatDate(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * Перевести указанную дату в строку по шаблону "dd.mm.yyyy"
     * @param date Дата
     */
    public static Date parseDate(String date) {
        return parseDate(date, "dd.mm.yyyy");
    }

    /**
     * Получить дату из строки по шаблону
     * @param date Дата
     * @param pattern Шаблон даты
     */
    public static Date parseDate(String date, String pattern) {
        Date result = null;
        try {
            result = new SimpleDateFormat(pattern).parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Увеличить дату на 1 день
     * @param date Дата
     */
    public static Date increaseDateByOneDay(Date date) {
        return increaseDateByXDays(date, 1);
    }

    /**
     * Увеличить дату на N дней
     * @param date Дата
     * @param days Кол-во дней
     */
    public static Date increaseDateByXDays(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, days);
        return calendar.getTime();
    }

    //=============================================================
    // Методы для экранирования спецсимволов

    /**
     * Экранирование обратного слэша и скобок
     * @param text Текст
     */
    public static String escapeMetaCharacters(String text) {
        text = text.replaceAll("\\\\", "\\\\\\\\"); // Экранировка \
        text = text.replaceAll("\\(", "\\\\("); // Экранировка (
        text = text.replaceAll("\\)", "\\\\)"); // Экранировка )
        return text;
    }

    /**
     * Экранирование обратного слэша и двойных кавычек
     * @param text Текст
     */
    public static String escapeSeleniumCharacters(String text) {
        text = text.replaceAll("\\\\", "\\\\\\\\"); // Экранировка \
        text = text.replaceAll("\"", "\\\\\\\""); // Экранировка "
        return text;
    }

    /**
     * Добавление спецсивола \s к цифрам в строке
     * (для совпадения в случае разделения больших чисел в группы по 3 цифры)
     * @param text Текст
     */
    public static String escapeSpacesFromNumbers(String text) {
        return text.replaceAll("(\\d)", "$1\\\\s*");
    }
}
